package org.sifebint.backend.services.datasources;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import net.jankovar.spring.aspects.InRole;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.sifebint.backend.dao.datasourcedescription.DataSourceDescriptionDao;
import org.sifebint.backend.exceptions.DriverNotFoundException;
import org.sifebint.backend.model.DataSourceDescription;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class DataSourceServiceImpl implements DataSourceService {
 
  private static final Logger logger = Logger.getLogger(DataSourceServiceImpl.class);
  
  private DataSourceDescriptionDao dataSourceDescriptionDao;
  
  private Map<Long, BasicDataSource> dataSources = new HashMap<Long, BasicDataSource>();
  
  private List<String> jdbcDriversList;
  
  @Override
  public DataSource getDataSource(long id) {
    
    BasicDataSource dataSource = dataSources.get(id);
    if (dataSource == null) {
      
      DataSourceDescription dataSourceDescription = dataSourceDescriptionDao.getDataSourceDescription(id);
      
      //check existence of jdbc driver
      try {
        Class.forName(dataSourceDescription.getJdbcDriver());
      } catch (ClassNotFoundException e) {
        throw new DriverNotFoundException(dataSourceDescription.getJdbcDriver(), e);
      }
      
      dataSource = new BasicDataSource();
      dataSource.setDriverClassName(dataSourceDescription.getJdbcDriver());
      dataSource.setUrl(dataSourceDescription.getUrl());
      dataSource.setPassword(dataSourceDescription.getPassword());
      dataSource.setUsername(dataSourceDescription.getUsername());

      dataSources.put(id, dataSource);
      
    }
    
    return dataSource;
  }
  
  public void destroy() {
    
    for (BasicDataSource dataSource : dataSources.values()) {
      try {
        dataSource.close();
      } catch (SQLException e) {
        logger.error("Problem closing data source.", e);
      }
    }
    
  }
  
  @Override
  public List<String> getJdbcDriversList() {
    return jdbcDriversList;
  }
  
  @InRole("sifebint-admin")
  @Override
  public void createDataSourceDescription(
      DataSourceDescription dataSourceDescription) {
    dataSourceDescriptionDao.createDataSourceDescription(dataSourceDescription);
  }

  @InRole("sifebint-admin")
  @Override
  public List<DataSourceDescription> getDataSourcesDescriptions() {
    return dataSourceDescriptionDao.getDataSourcesDescriptions();
  }

  @InRole("sifebint-admin")
  @Override
  public void updateDataSourceDescription(
      DataSourceDescription dataSourceDescription) {
    dataSources.remove(dataSourceDescription.getId());
    dataSourceDescriptionDao.updateDataSourceDescription(dataSourceDescription);
  }
  
  @InRole("sifebint-admin")
  @Override
  public void removeDataSourceDescription(long dataSourceDescriptionId) {
    dataSources.remove(dataSourceDescriptionId);
    dataSourceDescriptionDao.removeDataSourceDescription(dataSourceDescriptionId);
  }
  
  @Required
  public void setDataSourceDescriptionDao(
      DataSourceDescriptionDao dataSourceDescriptionDao) {
    this.dataSourceDescriptionDao = dataSourceDescriptionDao;
  }
  
  @Required
  public void setJdbcDriversListAsString(String jdbcDriversListAsString) {
    this.jdbcDriversList = Arrays.asList(jdbcDriversListAsString.split(":"));
  }

}
